import { isDate, isObject } from 'util'

// encode化
function encode(val: string): string {
  return encodeURIComponent(val) // 返回encode化的字符串，但特殊符号得到保留
    .replace(/%40/g, '@')
    .replace(/%3A/gi, ':')
    .replace(/%24/g, '$')
    .replace(/%2C/gi, ',')
    .replace(/%20/g, '+')
    .replace(/%5B/gi, '[')
    .replace(/%5D/gi, ']')
}

// 构建url
export function bindURL(url: string, params?: any): string {
  if (!params) return url // 若无params参数咋直接返回url

  const parts: string[] = [] // 参数零件集合

  // 遍历params参数
  Object.keys(params).forEach((key) => {
    let val = params[key] // 获取params当前项的值
    // 若值为null或undefined则忽略此次跳到下一层
    if (val === null || typeof val === 'undefined') return // forEach不具备真正return的能力，只会调到下一次循环，类似continue

    let values: string[] = [] // 参数值暂存区
    if (Array.isArray(val)) {
      // 参数值若为数组则将参数值放入暂存区
      values = val
      key += '[]' // 标识当前参数的值为数组元素
    } else {
      // 参数值为非数组则包装成数组
      values = [val]
    }

    // 统一处理参数暂存区中的值
    values.forEach((val) => {
      if (isDate(val)) {
        // 读取日期对象的具体时间
        val = val.toISOString()
      } else if (isObject(val)) {
        // 对象会被json化
        val = JSON.stringify(val)
      }
      // 若非数组，则将key对应val，若是数组则key为key[]，val则是遍历中的每一项，最终是[key[]=a, key[]=b]这种格式
      parts.push(`${encode(key)}=${encode(val)}`)
    })
  })

  let serializedParams = parts.join('&') // 参数序列化

  if (serializedParams) {
    const markIndex = url.indexOf('#') // 寻找url中的哈希
    if (~markIndex) {
      // 若找到哈希符号则去除哈希部分
      url = url.slice(0, markIndex)
    }
    url += (~url.indexOf('?') ? '&' : '?') + serializedParams // 将有效url与params结合
  }

  return url
}
